#include "include.h"
#include "bsp_iis.h"

#if I2S_EXT_EN

iis_cfg_t *iis_libcfg;

u8 i2s_16bit_clk_div[3][2] = {
  //bclkdiv  ////mclk_div
    {2-1, 8-1}, //64fs
    {4-1, 4-1}, //128fs
    {24-1, 2-1}, //256fs
};

u8 i2s_32bit_clk_div[3][2] = {
 //bclkdiv //mclk_div
    {8-1,1-1}, //64fs
    {2-1,4-1}, //128fs
    {4-1,2-1}, //256fs
};

u32 iis_tx_dma_addr_inc(void);
u32 iis_rx_dma_addr_inc(void);
void iis_irq_init(void);
#define IS_IIS_32BIT()    (IISCON0 & BIT(2))
#define IS_IIS_MASTER()   (CKB0(IISCON0,1))

AT(.com_text.iis_ext)
u32 iis_tx_dma_addr_inc(void)   //得到可用地址后,自增  //buf结构: TX_RX同时存在时前一半是TX,后一版半是RX, 如果只有TX或RX,则全部用于TX或RX
{
    u32 buf_idx = iis_libcfg->dma_cfg.txbuf_idx;
    u32 buf_len = iis_libcfg->dma_cfg.dmabuf_len;
    u32 addr = (u32)&(iis_libcfg->dma_cfg.dmabuf_ptr[buf_idx]);
    if ((iis_libcfg->mode & IISCFG_TX) && (iis_libcfg->mode & IISCFG_RX)) {  //tx rx 同时存在
        buf_idx += buf_len/4;
        if (buf_idx >= buf_len/2) {
            buf_idx = 0;
        }
    } else {  //only TX, buf可以扩大1倍
        buf_idx += buf_len/2;
        if (buf_idx >= buf_len) {
            buf_idx = 0;
        }
    }
    iis_libcfg->dma_cfg.txbuf_idx = buf_idx;
    return addr;
}

AT(.com_text.iis_ext)
u32 iis_rx_dma_addr_inc(void)   //得到可用地址后,自增  //buf结构: TX_RX同时存在时前一半是TX,后一版半是RX, 如果只有TX或RX,则全部用于TX或RX
{
    u32 buf_idx = iis_libcfg->dma_cfg.rxbuf_idx;
    u32 buf_len = iis_libcfg->dma_cfg.dmabuf_len;
    u32 addr = (u32)&(iis_libcfg->dma_cfg.dmabuf_ptr[buf_idx]);
    if ((iis_libcfg->mode & IISCFG_TX) && (iis_libcfg->mode & IISCFG_RX)) {   //TX_RX同时存在时前一半是TX,后一版半是RX
        buf_idx += buf_len/4;
        if (buf_idx >= buf_len) {
            buf_idx = buf_len/2;
        }
    } else {  //only TX, buf可以扩大1倍
        buf_idx += buf_len/2;
        if (buf_idx >= buf_len) {
            buf_idx = 0;
        }
    }
    iis_libcfg->dma_cfg.rxbuf_idx = buf_idx;
    return addr;
}

//iis_clk_ch: 0_dac_clk, 1_xosc52m, 3_syspll_clk
//iis_clk_div:  iis_clk_ch 配置为3时可以选分频系数
void iis_clk_set(u32 iis_clk_ch, u32 iis_clk_div)
{
    CLKGAT1  |= BIT(4);
    CLKGAT0  |= BIT(12);
    if(iis_clk_ch > 3)  {
        iis_clk_ch = 3;
    }
    if (iis_clk_div > 15) {
        iis_clk_div = 15;
    }
    CLKCON3 = (CLKCON3 & ~(0x0F<<8)) | (iis_clk_div << 8);
    CLKCON1 = (CLKCON1 & ~(0x03<<8)) | (iis_clk_ch << 8);
}

void iis_cfg_init(iis_cfg_t *cfg)
{
    u32 iisconsfr = 0;
    printf("%s\n", __func__);
    iis_libcfg = cfg;
    IIS_IO_INIT();
    iis_clk_set(0,0);     //i2s clk sel dac_clk
    SETB(IISCON0,16);     //clear tx pending
    SETB(IISCON0,17);     //clear rx pending
    IISCON0 = 0;
    if (iis_libcfg->mode & IISCFG_DMA) {  //dmabuf结构: TX_RX同时存在时前一半是TX,后一版半是RX, 如果只有TX或RX,则全部用于TX或RX.
        iis_irq_init();

        if (((iis_libcfg->mode & IISCFG_TXMASK) == IISCFG_RAMTX) && ((iis_libcfg->mode & IISCFG_RXMASK) == IISCFG_RAMRX)) { //RAM RX & RAMTX
            printf("iis ram tx & rx\n");
            iis_libcfg->dma_cfg.txbuf_idx = 0;
            iis_libcfg->dma_cfg.rxbuf_idx = iis_libcfg->dma_cfg.dmabuf_len/2;
            IISDMACNT = iis_libcfg->dma_cfg.samples;
            IISDMAIADR0 = iis_rx_dma_addr_inc();
            IISDMAIADR1 = iis_rx_dma_addr_inc();
            IISDMAOADR0 = iis_tx_dma_addr_inc();
            IISDMAOADR1 = iis_tx_dma_addr_inc();
        } else if (((iis_libcfg->mode & IISCFG_TXMASK) == IISCFG_RAMTX) && ((iis_libcfg->mode & IISCFG_RXMASK) != IISCFG_RAMRX)) {  //only RAMTX  DMA
            printf("iis only ram tx\n");
            iis_libcfg->dma_cfg.txbuf_idx = 0;
            IISDMACNT = iis_libcfg->dma_cfg.samples * 2;
            IISDMAOADR0 = iis_tx_dma_addr_inc();
            IISDMAOADR1 = iis_tx_dma_addr_inc();

        } else if (((iis_libcfg->mode & IISCFG_TXMASK) != IISCFG_RAMTX) && ((iis_libcfg->mode & IISCFG_RXMASK) == IISCFG_RAMRX)){  //ONLY RXMRX DMA
            printf("iis only ram rx\n");
            iis_libcfg->dma_cfg.rxbuf_idx = 0;
            IISDMACNT = iis_libcfg->dma_cfg.samples * 2;
            IISDMAIADR0 = iis_rx_dma_addr_inc();
            IISDMAIADR1 = iis_rx_dma_addr_inc();
        }
    }
    if (IIS_16BIT == iis_libcfg->bit_mode) {
        CLRB(iisconsfr,2);     //0: iis bit mode (0:16bit) at master function
        IISBAUD = (i2s_16bit_clk_div[iis_libcfg->mclk_sel][0] << 7) | i2s_16bit_clk_div[iis_libcfg->mclk_sel][1];
    } else if(IIS_32BIT == iis_libcfg->bit_mode) {
        SETB(iisconsfr,2);     //1: iis bit mode (1:32bit) at master function
        IISBAUD = (i2s_32bit_clk_div[iis_libcfg->mclk_sel][0] << 7) | i2s_32bit_clk_div[iis_libcfg->mclk_sel][1];
    }
    if (IIS_DATA_LEFT_JUSTIFIED == iis_libcfg->data_mode){
        CLRB(iisconsfr,3);     //0: left-justified mode (data delay 0 clock after WS change)
    } else if (IIS_DATA_NORMAL == iis_libcfg->data_mode){
        SETB(iisconsfr,3);     //1: IIS normal mode  (data delay 1 clock after WS change)
    }

    SETB(iisconsfr,10);     //dma out requet mask delay eanble (system very fast,need set this)
    if (iis_libcfg->mode & IISCFG_MASTER) {
        CLRB(iisconsfr,1);      //0 iis is master mode
    } else {
        SETB(iisconsfr,1);      //1 iis is slave mode
    }

    if (iis_libcfg->mclk_out_en) {
        SETB(iisconsfr,9);
    }

    if (iis_libcfg->mode & IISCFG_DMA) {
        if ((iis_libcfg->mode & IISCFG_TXMASK) == IISCFG_RAMTX) {
            printf("iis ram tx int en\n");
            SETB(iisconsfr,5);      //iis DMA output enable
            SETB(iisconsfr,7);      //dma output interrupt enable
            SETB(iisconsfr,4);      //data OUT source select: RAM
        }

        if ((iis_libcfg->mode & IISCFG_RXMASK) == IISCFG_RAMRX) {
            printf("iis ram rx int en\n");
            SETB(iisconsfr,6);      //iis DMA input enable
            SETB(iisconsfr,8);      //dma input interrupt enable
        }

        if ((iis_libcfg->mode & IISCFG_TXRXMASK) == IISCFG_RAMRX) { //只有RAMRX 需要把这位置起来才会KICK起来,同时有打开SRCTX时则可以不用设置它
            printf("iis only ram rx,bit4 set\n");
            SETB(iisconsfr,4);
        }
    }
    CLRB(iisconsfr,0);      //IIS EN,先屏蔽，由iis_start在需要时才打开

    if (iis_libcfg->mode & IISCFG_SRC) {
        printf("iis src out en\n");
        DACDIGCON0 |= BIT(23);
    } else {
        DACDIGCON0 &= ~BIT(23);
    }
    IISCON0 = iisconsfr;   //config iis sfor
}


void iis_start(void)
{
    printf("-->%s\n",__func__);
//    dac_spr_set(SPR_48000);
//    dac_fade_in();
    SETB(IISCON0,0);
}

void iis_stop(void)
{
    printf("-->%s\n",__func__);
    CLRB(IISCON0,0);
}


AT(.com_text.iis_ext)
void iis_isr_func(void)
{
    u32 cache_addr;
    u32 iiscon0 = IISCON0 & (~(BIT(16)|BIT(17)));
    if (IISCON0 & BIT(16)) {        //TX ISR
        IISCON0 = iiscon0|BIT(16);
        cache_addr = iis_tx_dma_addr_inc();
        IISDMAOADR1 = cache_addr;
        if (iis_libcfg->dma_cfg.iis_isr_tx_callbck) {
            iis_libcfg->dma_cfg.iis_isr_tx_callbck((void*)cache_addr,IISDMACNT,IISCON0 & BIT(2));
        }
    }

    if (IISCON0 & BIT(17)) {        //RX ISR
        IISCON0 = iiscon0|BIT(17);
        cache_addr = iis_rx_dma_addr_inc();
        IISDMAIADR1 = cache_addr;
        if (iis_libcfg->dma_cfg.iis_isr_rx_callbck) {
            iis_libcfg->dma_cfg.iis_isr_rx_callbck((void*)cache_addr,IISDMACNT,IISCON0 & BIT(2));
        }
    }
}

#define IRQ_I2S_VECTOR                  27
typedef void (*isr_t)(void);
isr_t register_isr(int vector, isr_t isr);
void iis_irq_init(void)
{
    printf("%s\n", __func__);
    register_isr(IRQ_I2S_VECTOR, iis_isr_func);
    PICPR &= ~BIT(IRQ_I2S_VECTOR);
	PICEN |= BIT(IRQ_I2S_VECTOR);
}

#endif //IIS_EXT_EN
